package com.lhkj.ct.framework.shiro.realm;

import com.lhkj.ct.base.enums.GlobalStatus;
import com.lhkj.ct.base.model.LoginUser;
import com.lhkj.ct.base.utils.IpUtils;
import com.lhkj.ct.base.utils.ServletUtils;
import com.lhkj.ct.framework.shiro.token.AccessTokenAuthenticationToken;
import com.lhkj.ct.meta.modules.auth.entity.TblUserIdentity;
import com.lhkj.ct.meta.modules.auth.service.UserIdentityService;
import com.lhkj.ct.meta.modules.patient.mapper.PatientMapper;
import com.lhkj.ct.meta.modules.patient.model.entity.TblPatient;
import eu.bitwalker.useragentutils.UserAgent;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;

/**
 * <p>
 *     第三方授权登录
 * </p>
 */
public class UserIdentityRealm extends AuthorizingRealm {

    private static final Logger log = LoggerFactory.getLogger(UserIdentityRealm.class);

    @Resource
    private PatientMapper patientMapper;

    @Resource
    private UserIdentityService userIdentityService;

    public UserIdentityRealm(CacheManager cacheManager) {
        super(cacheManager);
    }

    @Override
    public void setName(String name) {
        super.setName("user_identity_realm");
    }

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof AccessTokenAuthenticationToken;
    }

    /**
     * 角色权限和对应权限添加
     * Authorization授权，将数据库中的角色和权限授权给输入的用户名
     *
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        return authorizationInfo;
    }

    /**
     * 用户身份验证
     *
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        AccessTokenAuthenticationToken accessToken = (AccessTokenAuthenticationToken) token;
        TblUserIdentity identity = userIdentityService.getByIdentity(accessToken.getUserType(), accessToken.getIdentType(), accessToken.getIdentifier());
        if (identity == null) {
            throw new UnknownAccountException(String.format("未绑定第三方账号[%s]！", accessToken.getIdentType().getDesc()));
        }
        TblPatient patient = patientMapper.selectById(identity.getUserId());
        if (patient == null) {
            throw new UnknownAccountException(String.format("第三方账号[%s]所绑定账号已删除！", accessToken.getIdentType().getDesc()));
        }
        if (patient.getStatus() != GlobalStatus.NORMAL) {
            throw new DisabledAccountException("用户已封禁，请联系管理员！");
        }
        String ipAddr = IpUtils.getIpAddr();
        UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
        LoginUser loginUser = LoginUser.builder()
                .sessionKey(patient.getId())
                .userType(2)
                .userId(patient.getId())
                .loginName(patient.getAccount())
                .userName(patient.getPatName())
                .shiroRoles(null)
                .ipaddr(ipAddr)
                .loginLocation(IpUtils.getIpRegion(ipAddr))
                .loginTime(System.currentTimeMillis())
                .browser(userAgent.getBrowser().getName())
                .os(userAgent.getOperatingSystem().getName())
                .identifier(accessToken.getIdentifier())
                .build();
        return new SimpleAuthenticationInfo(loginUser, patient.getAccount(),
                 getName());
    }

    /* 设置自定义认证加密方式
     *
     * @param credentialsMatcher 默认加密方式
     */
    @Override
    public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
        // 设置自定义认证加密方式
        super.setCredentialsMatcher((token, info) -> true);
    }
}
